package com.liuqi.knet.remoting.transport.dispatcher;

import com.liuqi.knet.remoting.Channel;
import com.liuqi.knet.remoting.ChannelContext;
import com.liuqi.knet.remoting.ChannelHandler;
import com.liuqi.loggers.api.Logger;
import com.liuqi.loggers.facade.LoggersFacade;

/**
 * 通道事件执行器
 *
 * @author liuqi
 * @date 2025/2/8 17:34
 **/
public class ChannelEventRunnable implements Runnable {
    private static final Logger logger = LoggersFacade.getLogger(ChannelEventRunnable.class);

    private ChannelContext channelContext = new ChannelContext();

    private final ChannelHandler handler;
    private final Channel channel;
    private final ChannelState state;
    private final Throwable exception;
    private final Object message;

    public ChannelEventRunnable(Channel channel, ChannelHandler handler, ChannelState state) {
        this(channel, handler, state, null);
    }

    public ChannelEventRunnable(Channel channel, ChannelHandler handler, ChannelState state, Object message) {
        this(channel, handler, state, message, null);
    }

    public ChannelEventRunnable(Channel channel, ChannelHandler handler, ChannelState state, Throwable t) {
        this(channel, handler, state, null, t);
    }

    public ChannelEventRunnable(Channel channel, ChannelHandler handler, ChannelState state, Object message, Throwable exception) {
        this.channel = channel;
        this.handler = handler;
        this.state = state;
        this.message = message;
        this.exception = exception;
    }

    @Override
    public void run() {
        try {
            // set current channel
            channelContext.setCurrentChannel(channel);

            switch (state) {
                case CONNECTED:
                    handler.connected(channel);
                    break;
                case DISCONNECTED:
                    handler.disconnected(channel);
                    break;
                case SEND:
                    handler.send(channel, message);
                    break;
                case RECEIVED:
                    handler.received(channel, message);
                    break;
                case CAUGHT:
                    handler.caught(channel, exception);
                    break;
                default:
                    logger.warn("无效的Channel事件: " + state + ", message: " + message);
            }
        } catch (Throwable t) {
            logger.error(t.getMessage(), t);
        } finally {
            channelContext.removeCurrentChannel();
        }
    }

    public enum ChannelState {

        CONNECTED,

        DISCONNECTED,

        SEND,

        RECEIVED,

        CAUGHT
    }
}
